package com.gzhryc.event;

import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import com.gzhryc.common.DateTools;
import com.gzhryc.common.event.QuartzServer;
import com.gzhryc.common.event.TimerHandleService;
import com.gzhryc.event.dao.TimeTaskDao;
import com.gzhryc.event.dao.db.TimeTask;
import com.gzhryc.event.dao.enums.TimeTaskEnum;
import com.gzhryc.event.dto.TimeTaskSearch;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;

public class TimeTaskService {

	static TimeTaskDao timeTaskDao = new TimeTaskDao();
	
	public static List<TimeTask> findBySearch(TimeTaskSearch search,Integer pageNo,Integer pageLimit){
		Conditions condition = new Conditions(TimeTask.class);
		condition.and().likeBoth("name", search.getName());
		condition.and().likeBoth("handleClass", search.getHandleClass());
		condition.and().is("status", search.getStatus());
		condition.and().is("runType", search.getRunType());
		try {
			return timeTaskDao.findByCondition(condition, pageNo, pageLimit);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static Long countBySearch(TimeTaskSearch search){
		Conditions condition = new Conditions(TimeTask.class);
		condition.and().likeBoth("name", search.getName());
		condition.and().likeBoth("handleClass", search.getHandleClass());
		condition.and().is("status", search.getStatus());
		condition.and().is("runType", search.getRunType());
		try {
			return timeTaskDao.count(condition);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return 0L;
	}
	
	public static boolean add(TimeTask timeTask){
		timeTask.setStatus(TimeTaskEnum.Status.Usable.index());
		timeTask.setCreateDate(new Date());
		if(timeTask.getFrequency() == null){
			timeTask.setFrequency(0);
		}
		try {
			return timeTaskDao.insert(timeTask) > 0;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public static boolean deleteById(Long id){
		try {
			return timeTaskDao.deleteById(id) > 0;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public static void run(){
		//重置活动
		Conditions condition = new Conditions(TimeTask.class);
		condition.and().is("status", TimeTaskEnum.Status.Loading.index());
		
		TimeTask timeTask = new TimeTask();
		timeTask.setStatus(TimeTaskEnum.Status.Usable.index());
		
		try {
			timeTaskDao.updateNotNull(timeTask, condition);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		//获取所有Cron任务
		condition.and().is("status", TimeTaskEnum.Status.Usable.index());
		condition.and().is("runType", TimeTaskEnum.RunType.Cron.index());
		try {
			List<TimeTask> list = timeTaskDao.findByCondition(condition);
			if(list != null){
				QuartzServer.start();
				for(TimeTask item : list){
					if(StringUtils.isNotBlank(item.getQuartzCron()) 
							&& StringUtils.isNotBlank(item.getHandleClass())){
						JdbcSession.begin();
						try{
							//修改状态
							Conditions updateCondition = new Conditions();
							updateCondition.and().is("id", item.getId());
							updateCondition.and().is("status", TimeTaskEnum.Status.Usable.index());
							
							TimeTask updateEntity = new TimeTask();
							updateEntity.setStatus(TimeTaskEnum.Status.Loading.index());
							
							if(timeTaskDao.updateNotNull(updateEntity,updateCondition) > 0){
								@SuppressWarnings("unchecked")
								Class<? extends Job> clazz =(Class<? extends Job>)Class.forName(item.getHandleClass());
								Map<String,Object> data = new HashMap<String,Object>();
								data.put(TimeTask.class.getSimpleName(), item);
								QuartzServer.delayedRunJob(item.getQuartzCron(),clazz,data);
								JdbcSession.commit();
							}
						}catch(Exception e){
							e.printStackTrace();
							JdbcSession.rollback();
						}finally{
							JdbcSession.end();
						}
					}
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		//启动定时任务
		QuartzServer.start();
		QuartzServer.delayedRunJob("0 */1 * * * ?", OnecJob.class);
		QuartzServer.delayedRunJob("0 */1 * * * ?", ManyTimesJob.class);
	}
	
	public static class OnecJob implements Job {
		
		@Override
		public void execute(JobExecutionContext context) throws JobExecutionException {
			try{

				Conditions condition = new Conditions(TimeTask.class);
				condition.and().is("status", TimeTaskEnum.Status.Usable.index());
				condition.and().is("runType", TimeTaskEnum.RunType.Once.index());
		
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(new Date());
				//保障一个月以内的任务可执行
				condition.and().is("year", calendar.get(Calendar.YEAR));
				condition.and().is("month", calendar.get(Calendar.MONTH) + 1);
				condition.and().is("day", calendar.get(Calendar.DAY_OF_MONTH));
				
				List<TimeTask> list = timeTaskDao.findByCondition(condition);
				if(list != null){
					for(TimeTask item :list){
						Date runDate = DateUtils.parseDate(item.getRunDateStr(), new String[]{"yyyy-MM-dd HH:mm:ss"});
						Long delay = DateTools.differenceSecond(new Date(),runDate);
						//一个小时之内
						if(delay >= 0 && delay <= 3600){
							//修改状态
							Conditions updateCondition = new Conditions();
							updateCondition.and().is("id", item.getId());
							updateCondition.and().is("status", TimeTaskEnum.Status.Usable.index());
							
							TimeTask updateEntity = new TimeTask();
							updateEntity.setStatus(TimeTaskEnum.Status.Loading.index());
							
							if(timeTaskDao.updateNotNull(updateEntity,updateCondition) > 0){
								TimerHandleService.schedule(new HandlerTask(item), delay * 1000);
							}
						}
					}
				}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
	
	public static class ManyTimesJob implements Job {
		
		@Override
		public void execute(JobExecutionContext context) throws JobExecutionException {
			try{
				Conditions condition = new Conditions(TimeTask.class);
				condition.and().is("status", TimeTaskEnum.Status.Usable.index());
				condition.and().is("runType", TimeTaskEnum.RunType.ManyTimes.index());
		
				List<TimeTask> list = timeTaskDao.findByCondition(condition);
				if(list != null){
					for(TimeTask item :list){
						Date runDate = DateUtils.parseDate(item.getRunDateStr(), new String[]{"yyyy-MM-dd HH:mm:ss"});
						Long delay = DateTools.differenceSecond(runDate, new Date());
						//一个小时之内
						if(delay > 0 && delay <= 3600){
							//修改状态
							Conditions updateCondition = new Conditions();
							updateCondition.and().is("id", item.getId());
							updateCondition.and().is("status", TimeTaskEnum.Status.Usable.index());
							
							TimeTask updateEntity = new TimeTask();
							updateEntity.setStatus(TimeTaskEnum.Status.Loading.index());
							
							if(timeTaskDao.updateNotNull(updateEntity,updateCondition) > 0){
								TimerHandleService.schedule(new HandlerTask(item), (delay * 1000));
							}
						}
					}
				}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
	
	public static class HandlerTask extends TimerTask {
		
		final TimeTask timeTask;
		
		public HandlerTask(TimeTask timeTask){
			this.timeTask = timeTask;
		}

		@Override
		public void run() {
			if(timeTask != null && StringUtils.isNotBlank(timeTask.getHandleClass())){
				try {
					AbsTimeTaskHandler handler = (AbsTimeTaskHandler)Class.forName(timeTask.getHandleClass()).newInstance();
					if(handler != null){
						Conditions condition = new Conditions(TimeTask.class);
						condition.and().is("id", timeTask.getId());
						condition.and().is("status", TimeTaskEnum.Status.Loading.index());
						
						TimeTask updateEntity = new TimeTask();
						if(TimeTaskEnum.RunType.Once.index().equals(timeTask.getRunType())){
							updateEntity.setStatus(TimeTaskEnum.Status.End.index());
						}else if(TimeTaskEnum.RunType.ManyTimes.index().equals(timeTask.getRunType())){
							updateEntity.setStatus(TimeTaskEnum.Status.Usable.index());
						}
						//修改状态
						if(timeTaskDao.updateNotNull(updateEntity,condition) > 0){
							handler.execute(timeTask);
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		
	}
}
